/*
Copyright (C) 2010 Andrew Dieffenbach (www.puzzud.com).

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

package com.puzzud.engine.utility;

import java.awt.*;
import java.awt.event.*;
import javax.swing.JPanel;
import javax.swing.ImageIcon;


import com.puzzud.engine.video.*;
import com.puzzud.engine.audio.*;
import com.puzzud.engine.input.*;

//public abstract class GameShell extends Applet implements Runnable, KeyListener, MouseListener, MouseMotionListener
public abstract class GameShell extends JPanel implements Runnable, KeyListener, MouseListener, MouseMotionListener
{
	Thread thread;
	
	VideoDisplay videoDisplay;
	public Graphics graphicsContext;
	
	int frameCount;
	int frameRate;
	long startTime;

	InputKeyboard keyboard;
	InputMouse mouse;
	
	public void init()
	{
		videoDisplay = initializeVideoDisplay();
		
		frameCount = 0;
		frameRate = 0;
		startTime = System.currentTimeMillis();
		
		keyboard = new InputKeyboard();
		mouse = new InputMouse();
		
		addKeyListener( this );
		addMouseListener( this );
		addMouseMotionListener( this );
		
		setFocusable(true);
		initialize();
	}
	
	public void run()
	{
                /*
		Thread t = Thread.currentThread();
		
		while( t == thread )
		{
			try
			{
				Thread.sleep( 1000 / videoDisplay.getFrameRate() );
			}
			catch( InterruptedException e )
			{
				e.printStackTrace();
			}
			
			// Game logic here:
			loop();
			
			// Get user input.
			keyboard.read();
			mouse.read();
			
			repaint();
		}
		*/
		
		long beforeTime, timeDiff, sleep;

		beforeTime = System.currentTimeMillis();

		while( true )
		{
			loop();

                        // Get user input.
			keyboard.read();
			mouse.read();

			repaint();

			timeDiff = System.currentTimeMillis() - beforeTime;
			sleep = videoDisplay.getFrameRate() / 2 - timeDiff;

			if( sleep < 0 )
				sleep = 10;
			
			try
			{
				Thread.sleep( sleep );
			}
			catch( InterruptedException e )
			{
				System.out.println( "interrupted" );
			}

			beforeTime = System.currentTimeMillis();
		}
		
	}
	
	
	public void update( Graphics g )
	{
            /*
		// Calculate frame rate (frames per second or 1000 milliseconds).
		frameCount++;
		if( System.currentTimeMillis() > startTime + 1000 )
		{
			startTime = System.currentTimeMillis();
			frameRate = frameCount;
			frameCount = 0;
		}
		*/
                //repaint();
		//paint( g );

            draw();

            //System.out.println( "FUCK");
	}
	
	public void paint( Graphics g )
	{
		super.paint( g );
		
		graphicsContext = g;
	}
	
	public void paintComponent( Graphics g )
	{
		super.paintComponent( g );
		
		graphicsContext = g;
		
		videoDisplay.clear();
		
		draw();
		
		videoDisplay.display();
		
		Toolkit.getDefaultToolkit().sync();
		g.dispose();
	}
	
	public abstract void initialize();
	public abstract void shutdown();
	public abstract void loop();
	public abstract void draw();
	
	public abstract VideoDisplay initializeVideoDisplay();
	
	public void addNotify()
	{
		super.addNotify();
		
		init();
		
		thread = new Thread( this );
		thread.start();
	}
	
	public void stop()
	{
		thread = null;
	}
	
	public VideoDisplay getVideoDisplay()
	{
		return( videoDisplay );
	}
	
	public InputKeyboard getKeyboard()
	{
		return( keyboard );
	}
	
	public InputMouse getMouse()
	{
		return( mouse );
	}
	
	public void keyPressed( KeyEvent e )
	{
		//System.out.println( "KEY PRESSED:  " + e.getKeyCode() );
		keyboard.pressKey( e.getKeyCode() );
	}

	public void keyReleased( KeyEvent e )
	{
		//System.out.println( "KEY RELEASED: " + e.getKeyCode() );
		keyboard.releaseKey( e.getKeyCode() );
	}

	public void keyTyped( KeyEvent e )
	{
		
	}
	
	public void mouseEntered( MouseEvent e )
	{
		mouse.setPosition( e.getX(), e.getY() );
                mouse.setVelocity( 0, 0 );
	}
	
	public void mouseExited( MouseEvent e )
	{
		mouse.setPosition( e.getX(), e.getY() );    // NOTE: Should this happen?
                mouse.setVelocity( 0, 0 );
	}
	
	public void mouseClicked( MouseEvent e )
	{
		
	}
	
	public void mousePressed( MouseEvent e )
	{
		int x = e.getX();
		int y = e.getY();

                //System.out.println( "mousePressed(" + ( e.getButton() - 1 ) + ")" );
		
		mouse.pressButton( e.getButton() - 1 );
		mouse.setPosition( x, y );

                mouse.setDraggable( true );
                mouse.setDragOrigin( x, y );
	}
	
	public void mouseReleased( MouseEvent e )
	{
		int x = e.getX();
		int y = e.getY();
		
		mouse.releaseButton( e.getButton() - 1 );

                if( mouse.isDragging() )
                {
                    mouse.setDragEnd( x, y );
                }
	}
	
	public void mouseMoved( MouseEvent e )
	{
		int x = e.getX();
		int y = e.getY();

                // First take care of drag info.
                if( mouse.isDragEnded() == true )
                {
                    mouse.setDragEnd( mouse.getXPosition(), mouse.getYPosition() );
                }
		
		mouse.setVelocity( x - mouse.getXPosition(), y - mouse.getYPosition() );
		mouse.setPosition( x, y );

		mouse.setDraggable( false );
                mouse.setDragging( false );
	}
	
	public void mouseDragged( MouseEvent e )
	{
		int x = e.getX();
		int y = e.getY();
		
		mouse.setVelocity( x - mouse.getXPosition(), y - mouse.getYPosition() );
		mouse.setPosition( x, y );

		mouse.setDraggable( true );
                mouse.setDragging( true );
		
		
		//this.repaint();
	}
	
	public void output( String s )
	{
		//showStatus( s );
	}
	
	/*
	public URL getCodeBase()
	{
		return( new URL() );
	}
	*/
}
